home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume3 / xenix-fuser < prev    next >
Encoding:
Internet Message Format  |  1989-02-03  |  25.5 KB

  1. Path: xanth!mcnc!rutgers!gatech!bloom-beacon!husc6!m2c!necntc!ncoast!allbery
  2. From: jfh@rpp386.UUCP (The Beach Bum)
  3. Newsgroups: comp.sources.misc
  4. Subject: v03i090: fuser for 386 xenix (+ repost of Unix PC version)
  5. Message-ID: <8807130006.AA13998@rpp386.UUCP>
  6. Date: 13 Jul 88 05:06:38 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: jfh@rpp386.UUCP (The Beach Bum)
  9. Lines: 1008
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. Posting-number: Volume 3, Issue 90
  13. Submitted-by: "The Beach Bum" <jfh@rpp386.UUCP>
  14. Archive-name: xenix-fuser
  15.  
  16. brando -
  17.  
  18. ha!  rich $alz last hacked on this before me so far as i can tell.  this
  19. probably belongs to him (for posting) but working on 386 xenix only seems
  20. as .misc as it gets.
  21.  
  22. the next major submission will be a reimplementation of crash which runs
  23. on, you guessed it, 386 xenix only!  i'm not into writing portable code
  24. this week.
  25.  
  26. - john.
  27. --
  28. #! /bin/sh
  29. # This is a shell archive, meaning:
  30. # 1. Remove everything above the #! /bin/sh line.
  31. # 2. Save the resulting text in a file.
  32. # 3. Execute the file with /bin/sh (not csh) to create:
  33. #    README
  34. #    fuser.1
  35. #    Makefile
  36. #    fuser.c.sco
  37. #    fuser.c.u-pc
  38. # This archive created: Sun Jul  3 11:21:31 1988
  39. # By:    The Beach Bum (Big "D" Home for Wayward Hackers)
  40. export PATH; PATH=/bin:/usr/bin:$PATH
  41. if test -f 'README'
  42. then
  43.     echo shar: "will not over-write existing file 'README'"
  44. else
  45. sed 's/^X//' << \SHAR_EOF > 'README'
  46. X[  This has been ported to SCO Xenix for the Intel 80386.  There are
  47. X   two versions of the program.  The differences were large than the
  48. X   entire sharchive, so I saw no point in including context diffs.
  49. X   The Makefile should explain everything.  Ideally, the machine
  50. X   dependencies would be separated into different files. - john. ]
  51. X
  52. X[  This program takes a filename, searches the kernel's open file
  53. X   table, and determines who has that file open.  You can to kill the
  54. X   offending process(es).  This is useful for backups, e.g.  A port of
  55. X   this to BSD and other Unices would be nice.  --r$  ]
  56. X
  57. XHere is the latest source to my version of the fuser(1M) command, written
  58. Xand running on the Unix PC.  A man page and makefile are included.
  59. X
  60. XVerify that the macros in "Makefile" are correct for you (LBIN, for example
  61. Xshould be where you want the program to be installed), and run make AS ROOT.
  62. XIt is important to do the make as root so that the resulting program will
  63. Xhave the set-uid bit set, allowing it to read the kernel's memory.
  64. X
  65. X
  66. XSome notes to anyone who wants to port this program to something other
  67. Xthan the Unix PC:
  68. X
  69. XThe Unix PC has "tunable kernel parameters", which mean that things that
  70. Xare constants on most older Unix systems are variable.  This version of
  71. Xfuser reads the values of these variables from the kernel's memory.  I have
  72. Xtried to make most of this transparent, for ease of porting to a more plain-
  73. Xvanilla Unix.  For example, I have 'int' varialbes called 'NOFILE', 'NPROC',
  74. Xetc., which emulate the #defines present in 'standard' Unix.  To make it
  75. Xrun on such systems, it should be possible to remove these variables and
  76. Xthe code that sets them, and the program will use the #defines from
  77. X<sys/*.h>.  The only other significant change is that because NOFILE is
  78. Xvariable, the u_ofile field in the user structure is a pointer rather than
  79. Xan array.  This means that you can delete the code that copies the u_ofile
  80. Xlist since it is already right in the user structure.
  81. X
  82. X
  83. X                    -=] Ford [=-
  84. X
  85. X"GNU does not eliminate            (In Real Life:  Michael Ditto)
  86. Xall the world's problems,        kenobi!ford@crash.CTS.COM
  87. Xonly some of them." -rms        ...!crash!kenobi!ford
  88. X
  89. X
  90. XHere's the shar file:
  91. SHAR_EOF
  92. fi
  93. if test -f 'fuser.1'
  94. then
  95.     echo shar: "will not over-write existing file 'fuser.1'"
  96. else
  97. sed 's/^X//' << \SHAR_EOF > 'fuser.1'
  98. X.TH FUSER 1M
  99. X.SH NAME
  100. Xfuser \- find processes using a file or filesystem
  101. X.SH SYNOPSIS
  102. X.B fuser
  103. X[-ku] files [...]
  104. X.SH DESCRIPTION
  105. X.I Fuser
  106. Xsearches the kernel's internal tables to find all processes that are
  107. Xaccessing the listed
  108. X.I files.
  109. XIf one of the
  110. X.I files
  111. Xis a block special file (such as a disk) then fuser finds processes that
  112. Xare accessing any file on that device.
  113. X.P
  114. X.I Fuser
  115. Xlists on its standard output the process ID of each process found
  116. Xto be using any of the files
  117. Xspecified.  The process IDs will be followed by the letters
  118. X.B c,
  119. X.B r,
  120. Xor
  121. X.B p,
  122. Xif the file is open as the current directory, root directory, or
  123. Xparent directory of the process, respectively.  (The kernel has a process'
  124. Xparent directory "open" for internal use under certain conditions.)
  125. X.SH OPTIONS
  126. XThe -k option causes
  127. X.I fuser
  128. Xto attempt to kill each process found with the SIGKILL signal (normal
  129. Xpermission controls apply; see kill(2)).
  130. X.P
  131. XThe -u option causes
  132. X.I fuser
  133. Xto print, in parentheses, the user ID of the owner of each process listed.
  134. X.P
  135. XOptions may be re-specified between filenames; a '-' argument by itself
  136. Xturns off the -k and -u options.
  137. X.P
  138. XThe process IDs are written to standard output, one line per file searched
  139. Xfor.  Other output is written to standard error.
  140. X.SH EXAMPLES
  141. Xfuser /tmp/foo
  142. X.br
  143. X.RS
  144. XThis prints the process IDs of all processes that have the file /tmp/foo open.
  145. X.RE
  146. X.P
  147. Xfuser -u /dev/fp021
  148. X.br
  149. X.RS
  150. XThis finds all processes that are accessing any file on the disk /dev/fp021.
  151. XThe process IDs and user names of the process owners are listed.
  152. XThis is useful to find out why a disk can not be unmounted.
  153. X.RE
  154. X.P
  155. Xfuser -k /dev/fp021
  156. X.br
  157. Xumount /dev/fp021
  158. X.br
  159. X.RS
  160. XIf run by super-user, this kills all processes that are preventing
  161. Xthe disk /dev/fp021 from being unmounted, and then unmounts the disk.
  162. X.RE
  163. X.SH BUGS
  164. XIf a process's user area is swapped (happens on some versions of UNIX)
  165. Xfuser will print a warning and ignore that process.
  166. SHAR_EOF
  167. fi
  168. if test -f 'Makefile'
  169. then
  170.     echo shar: "will not over-write existing file 'Makefile'"
  171. else
  172. sed 's/^X//' << \SHAR_EOF > 'Makefile'
  173. XSHELL=/bin/sh
  174. XLBIN=/usr/local/bin
  175. XINSTALL=cp
  176. X
  177. X# Set this to version of .c file you want.  fuser.c.sco is for SCO Xenix
  178. X# for a 386.  fuser.c.u-pc is for Unix System V on an Unix PC.
  179. XFUSER=fuser.c.sco
  180. X# FUSER=fuser.c.u-pc
  181. X
  182. X# Set this to group which owns /dev/swap, /dev/mem and /dev/kmem.  Those
  183. X# files MUST be readable by that group.  Otherwise, the program must be
  184. X# SUID root to be used by anyone other than root, or other special
  185. X# arrangements must be made, all of which could compromise the system.
  186. X# ADMIN=root
  187. XADMIN=sysinfo
  188. X
  189. X# Debugging flags
  190. X# CFLAGS=-DDEBUG -g
  191. X# LDFLAGS=-g
  192. X
  193. X# Production flags
  194. XCFLAGS=-O
  195. XLDFLAGS=-s
  196. X
  197. Xfuser: fuser.o
  198. X    $(CC) $(LDFLAGS) -o fuser fuser.o
  199. X
  200. Xinstall: fuser
  201. X    $(INSTALL) fuser $(LBIN)
  202. X    chown root $(LBIN)/fuser
  203. X    chgrp $(ADMIN) $(LBIN)/fuser
  204. X    chmod 2711 $(LBIN)/fuser
  205. X
  206. Xclean:
  207. X    -rm -f *.o core
  208. X
  209. Xclobber: clean
  210. X    -rm -f fuser.c fuser $(LBIN)/fuser
  211. X
  212. Xfuser.c: $(FUSER)
  213. X    cp $(FUSER) fuser.c
  214. SHAR_EOF
  215. fi
  216. if test -f 'fuser.c.sco'
  217. then
  218.     echo shar: "will not over-write existing file 'fuser.c.sco'"
  219. else
  220. sed 's/^X//' << \SHAR_EOF > 'fuser.c.sco'
  221. X/************************************************************
  222. X *
  223. X * This program was written by me, Mike "Ford" Ditto, and
  224. X * I hereby release it into the public domain in the interest
  225. X * of promoting the development of free, quality software
  226. X * for the hackers and users of the world.
  227. X *
  228. X * Feel free to use, copy, modify, improve, and redistribute
  229. X * this program, but keep in mind the spirit of this
  230. X * contribution; always provide source, and always allow
  231. X * free redistribution (shareware is fine with me).  If
  232. X * you use a significant part of this code in a program of
  233. X * yours, I would appreciate being given the appropriate
  234. X * amount of credit.
  235. X *                -=] Ford [=-
  236. X *
  237. X ************************************************************/
  238. X
  239. X#include <stdio.h>
  240. X#include <fcntl.h>
  241. X#include <ctype.h>
  242. X#include <pwd.h>
  243. X#include <sys/types.h>
  244. X#include <sys/param.h>
  245. X#include <sys/sysmacros.h>
  246. X#include <sys/stat.h>
  247. X#include <sys/inode.h>
  248. X#include <sys/file.h>
  249. X#include <sys/seg.h>
  250. X#include <sys/page.h>
  251. X#include <sys/text.h>
  252. X#include <sys/proc.h>
  253. X#include <sys/signal.h>
  254. X#include <sys/dir.h>
  255. X#include <sys/user.h>
  256. X#include <sys/var.h>
  257. X
  258. Xextern char *sbrk();
  259. Xextern long lseek();
  260. Xextern void perror(), exit();
  261. Xextern struct passwd *getpwuid();
  262. Xextern char *malloc();
  263. X
  264. X
  265. Xchar *progname;
  266. X
  267. X#define inodeaddr (mysyms[0].xl_value)
  268. X#define fileaddr (mysyms[1].xl_value)
  269. X#define procaddr (mysyms[2].xl_value)
  270. X#define varaddr (mysyms[3].xl_value)
  271. X
  272. Xstruct xlist mysyms[] =
  273. X{
  274. X    { 0,0,0,"_inode" },
  275. X    { 0,0,0,"_file" },
  276. X    { 0,0,0,"_proc" },
  277. X    { 0,0,0,"_v" },
  278. X    { 0,0,0,(char *)0 }
  279. X};
  280. X
  281. Xchar buf[BUFSIZ];
  282. X
  283. Xint kmem, mem, swap, kflag, uflag;
  284. Xint NINODE, NFILE, NPROC;
  285. X
  286. Xstruct inode *inodep;
  287. Xstruct file *filep;
  288. Xstruct proc *procp;
  289. Xstruct var *var;
  290. X
  291. X
  292. X/* main program for fuser(1M), a program which lists */
  293. X/* processes that are using the given file(s) */
  294. Xmain(argc, argv)
  295. Xint argc;
  296. Xchar *argv[];
  297. X{
  298. X    int status=0;
  299. X
  300. X    progname = *argv;
  301. X
  302. X    setup();
  303. X
  304. X    while (++argv,--argc)
  305. X    if ((*argv)[0]=='-')
  306. X    {
  307. X        register char c, *i;
  308. X
  309. X        kflag=uflag=0;
  310. X
  311. X        i = *argv+1;
  312. X        while (c= *i++) switch(c)
  313. X        {
  314. X        case 'k':
  315. X        ++kflag;
  316. X        break;
  317. X        case 'u':
  318. X        ++uflag;
  319. X        break;
  320. X        default:
  321. X        fprintf(stderr, "%s: bad flag `-%c'\n", progname, c);
  322. X        fprintf(stderr,
  323. X            "Usage: %s [-ku] files [[-] [-ku] files]\n",
  324. X            progname);
  325. X        return -1;
  326. X        }
  327. X    }
  328. X    else {
  329. X        printf ("%s: ", *argv);
  330. X        status += fuser(*argv);
  331. X        putchar ('\n');
  332. X    }
  333. X    return status;
  334. X}
  335. X
  336. X
  337. X/* a fast, zeroizing, memory allocator for things */
  338. X/* that will never need to be freed */
  339. Xchar *myalloc(nbytes)
  340. Xlong nbytes;
  341. X{
  342. X    register char *ptr;
  343. X
  344. X    ptr = malloc((unsigned) nbytes);
  345. X    if (! ptr)
  346. X    {
  347. X    sprintf(buf, "%s: no memory!", progname);
  348. X    perror(buf);
  349. X    exit(1);
  350. X    }
  351. X    memset (ptr, 0, nbytes);
  352. X
  353. X    return ptr;
  354. X}
  355. X
  356. X
  357. X/* one-time setup of main data structures from the kernel */
  358. Xsetup()
  359. X{
  360. X    if ( (kmem=open("/dev/kmem", O_RDONLY)) < 0 )
  361. X    {
  362. X    sprintf(buf, "%s: can't open /dev/kmem", progname);
  363. X    perror(buf);
  364. X    exit(1);
  365. X    }
  366. X
  367. X    if ( (mem=open("/dev/mem", O_RDONLY)) < 0 )
  368. X    {
  369. X    sprintf(buf, "%s: can't open /dev/mem", progname);
  370. X    perror(buf);
  371. X    exit(1);
  372. X    }
  373. X
  374. X    if ( (swap=open("/dev/swap", O_RDONLY)) < 0 )
  375. X    {
  376. X    sprintf(buf, "%s: can't open /dev/swap", progname);
  377. X    perror(buf);
  378. X    exit(1);
  379. X    }
  380. X
  381. X    if (xlist("/xenix", mysyms))
  382. X    {
  383. X    sprintf(buf, "%s: can't xlist /xenix", progname);
  384. X    perror(buf);
  385. X    exit(1);
  386. X    }
  387. X
  388. X    setuid(getuid());
  389. X
  390. X#ifdef DEBUG
  391. X    fprintf(stderr, "inode:    0x%08lx\n", inodeaddr);
  392. X    fprintf(stderr, "file:    0x%08lx\n", fileaddr);
  393. X    fprintf(stderr, "proc:    0x%08lx\n", procaddr);
  394. X    fprintf(stderr, "var:       0x%08lx\n", varaddr);
  395. X#endif DEBUG
  396. X
  397. X    var = (struct var *)myalloc((long) sizeof (struct var));
  398. X    kcopy((char *)var, varaddr, (long) sizeof (struct var));
  399. X
  400. X    NINODE = var->v_inode;
  401. X    NFILE = var->v_file;
  402. X    NPROC = var->v_proc;
  403. X
  404. X#ifdef DEBUG
  405. X    fprintf(stderr, "NOFILE:    %d\n", NOFILE);
  406. X    fprintf(stderr, "NINODE:    %d\n", NINODE);
  407. X    fprintf(stderr, "NFILE:    %d\n", NFILE);
  408. X    fprintf(stderr, "NPROC:    %d\n", NPROC);
  409. X#endif DEBUG
  410. X
  411. X    inodep = (struct inode *)myalloc((long) sizeof (struct inode) * NINODE);
  412. X    filep = (struct file *)myalloc((long) sizeof (struct file) * NFILE);
  413. X    procp = (struct proc *)myalloc((long) sizeof (struct proc) * NPROC);
  414. X
  415. X    kcopy((char *)inodep, inodeaddr, (long) sizeof (struct inode) * NINODE);
  416. X    kcopy((char *)filep, fileaddr, (long) sizeof (struct file) * NFILE);
  417. X    kcopy((char *)procp, procaddr, (long) sizeof (struct proc) * NPROC);
  418. X}
  419. X
  420. X
  421. X/* copy bytes from physical address space to this process */
  422. Xpcopy(caddr, paddr, nbytes)
  423. Xchar *caddr;
  424. Xlong paddr;
  425. Xlong nbytes;
  426. X{
  427. X    if ( lseek(mem, paddr, 0)<0L ||
  428. X    read(mem, caddr, (unsigned)nbytes) != nbytes )
  429. X    {
  430. X    sprintf(buf, "%s: can't read /dev/mem", progname);
  431. X    perror(buf);
  432. X    exit(1);
  433. X    }
  434. X}
  435. X
  436. X
  437. X/* copy bytes from kernel address space to this process */
  438. Xkcopy(caddr, kaddr, nbytes)
  439. Xchar *caddr;
  440. Xlong kaddr;
  441. Xlong nbytes;
  442. X{
  443. X    if ( lseek(kmem, kaddr, 0)<0L ||
  444. X    read(kmem, caddr, (unsigned)nbytes) != nbytes )
  445. X    {
  446. X    sprintf(buf, "%s: can't read /dev/kmem", progname);
  447. X    perror(buf);
  448. X    exit(1);
  449. X    }
  450. X}
  451. X
  452. Xfindu (proc, slot, user)
  453. Xstruct    proc    *proc;
  454. Xint    slot;
  455. Xstruct    user    *user;
  456. X{
  457. X    long    swapaddr;
  458. X    int    i;
  459. X
  460. X    if ((proc->p_flag & (SSWAP|SSPART)) || ! (proc->p_flag & SLOAD)) {
  461. X        swapaddr = proc->p_addr[0].te_frameno * NBPC;
  462. X        lseek (swap, swapaddr, 0);
  463. X        if (read (swap, user, sizeof *user) < 0)
  464. X            return (0);
  465. X    } else {
  466. X        lseek (mem, proc->p_addr[0].te_frameno * NBPC, 0);
  467. X        if (read (mem, user, sizeof *user) < 0)
  468. X            return (0);
  469. X    }
  470. X    if ((user->u_procp - (struct proc *) procaddr) == slot)
  471. X        return (1);
  472. X    else
  473. X        return (0);
  474. X}
  475. X/* Return a pointer to a local copy of the user structure */
  476. X/* for process number `procidx'.  Returns NULL if procidx */
  477. X/* refers to an invalid (not-in-use or otherwise) slot. */
  478. Xstruct user *getuser(procidx)
  479. Xint procidx;
  480. X{
  481. X    static struct user **users;
  482. X    struct file **ofile;
  483. X    long upage;
  484. X
  485. X#ifdef    DEBUG
  486. X    fprintf (stderr, "Looking for upage for proc %d\n", procidx);
  487. X#endif
  488. X    if (!procp[procidx].p_stat ||
  489. X    procp[procidx].p_stat == SIDL ||
  490. X    procp[procidx].p_stat == SZOMB)
  491. X    return 0;
  492. X
  493. X    if (!users)
  494. X    users = (struct user **)myalloc((long) sizeof (struct user *) * NPROC);
  495. X
  496. X    if (!users[procidx])
  497. X    {
  498. X    /* allocate and copy in the user structure */
  499. X    users[procidx] = (struct user *)myalloc((long) sizeof (struct user));
  500. X    if (! findu (&procp[procidx], procidx, users[procidx]))
  501. X        return 0;
  502. X    }
  503. X    return users[procidx];
  504. X}
  505. X
  506. X
  507. X/* find all users of the file `name' */
  508. Xfuser(name)
  509. Xchar *name;
  510. X{
  511. X    register i;
  512. X    int filesys;
  513. X    struct stat Stat;
  514. X
  515. X    if (stat(name, &Stat))
  516. X    {
  517. X    sprintf(buf, "%s: can't stat %s", progname, name);
  518. X    perror(buf);
  519. X    return 1;
  520. X    }
  521. X
  522. X    /* see if we are looking for a whole filesystem */
  523. X    filesys = ((Stat.st_mode & S_IFMT) == S_IFBLK);
  524. X
  525. X#ifdef DEBUG
  526. X    if (filesys)
  527. X    fprintf(stderr, "looking for files on dev=%d,%d\n",
  528. X        bmajor(Stat.st_rdev), minor(Stat.st_rdev));
  529. X    else
  530. X    fprintf(stderr, "looking for dev=%d,%d, ino=%d\n",
  531. X        bmajor(Stat.st_dev), minor(Stat.st_dev), Stat.st_ino);
  532. X#endif DEBUG
  533. X
  534. X    for ( i=0 ; i<NINODE ; ++i )
  535. X    {
  536. X    if ( inodep[i].i_count &&
  537. X         ((filesys && (inodep[i].i_dev == Stat.st_rdev))
  538. X         || (inodep[i].i_dev == Stat.st_dev &&
  539. X            inodep[i].i_number == Stat.st_ino)) )
  540. X    {
  541. X#ifdef DEBUG
  542. X        fprintf(stderr, "Found it!  inodep[%d], i_size is %ld\n",
  543. X           i, inodep[i].i_size);
  544. X#endif DEBUG
  545. X
  546. X        iuser((struct inode *)inodeaddr + i);
  547. X    }
  548. X    }
  549. X
  550. X    return 0;
  551. X}
  552. X
  553. X
  554. X#define CHECK(kaddr, type) if (kaddr==kinode) { if (++flag==1) printf(" %d", procp[i].p_pid); if (type) putchar(type); }
  555. X
  556. X/* find all users of the inode at kernel address `kinode' */
  557. Xiuser(kinode)
  558. Xstruct inode *kinode;
  559. X{
  560. X    register int i, j;
  561. X    int flag;
  562. X    struct user *user;
  563. X    struct passwd *pwd;
  564. X    struct text text;
  565. X
  566. X#ifdef DEBUG
  567. X    fprintf(stderr, "Looking for users of inode at kernel address 0x%08lx\n",
  568. X        kinode);
  569. X#endif DEBUG
  570. X
  571. X    for ( i=0 ; i<NPROC ; ++i )
  572. X    if (user = getuser(i))
  573. X    {
  574. X#ifdef DEBUG
  575. X        fprintf(stderr, "%03d: pid=%5d addr[0]=%05x addr[1]=%05x\n",
  576. X            i, procp[i].p_pid, procp[i].p_addr[0], procp[i].p_addr[1]);
  577. X#endif DEBUG
  578. X
  579. X#ifdef DEBUG
  580. X        fprintf(stderr, "    user = 0x%08lx\n", user);
  581. X#endif DEBUG
  582. X
  583. X        fflush(stderr);
  584. X        flag=0;
  585. X        if (procp[i].p_textp) {
  586. X        kcopy((char *)&text, procp[i].p_textp, (long) sizeof (struct text));
  587. X        CHECK(text.x_iptr, 't');
  588. X        }
  589. X
  590. X        CHECK(user->u_cdir, 'c');
  591. X        CHECK(user->u_rdir, 'r');
  592. X        CHECK(user->u_pdir, 'p');
  593. X
  594. X        for ( j=0 ; !flag && j<NOFILE ; ++j )
  595. X        if (user->u_ofile[j])
  596. X            CHECK(filep[user->u_ofile[j]-(struct file *)fileaddr].f_inode, 0);
  597. X        fflush(stdout);
  598. X
  599. X        if (flag)
  600. X        {
  601. X        if (uflag)
  602. X        {
  603. X            if ( (pwd=getpwuid((int)procp[i].p_uid)) )
  604. X            fprintf(stderr, "(%s)", pwd->pw_name);
  605. X            else
  606. X            fprintf(stderr, "(%d)", procp[i].p_uid);
  607. X        }
  608. X        if (kflag && procp[i].p_pid)
  609. X            if (kill(procp[i].p_pid, SIGKILL))
  610. X            {
  611. X            sprintf(buf, "%s: can't kill process %d",
  612. X                progname, procp[i].p_pid);
  613. X            perror(buf);
  614. X            }
  615. X        }
  616. X    }
  617. X}
  618. SHAR_EOF
  619. fi
  620. if test -f 'fuser.c.u-pc'
  621. then
  622.     echo shar: "will not over-write existing file 'fuser.c.u-pc'"
  623. else
  624. sed 's/^X//' << \SHAR_EOF > 'fuser.c.u-pc'
  625. X/************************************************************
  626. X *
  627. X * This program was written by me, Mike "Ford" Ditto, and
  628. X * I hereby release it into the public domain in the interest
  629. X * of promoting the development of free, quality software
  630. X * for the hackers and users of the world.
  631. X *
  632. X * Feel free to use, copy, modify, improve, and redistribute
  633. X * this program, but keep in mind the spirit of this
  634. X * contribution; always provide source, and always allow
  635. X * free redistribution (shareware is fine with me).  If
  636. X * you use a significant part of this code in a program of
  637. X * yours, I would appreciate being given the appropriate
  638. X * amount of credit.
  639. X *                -=] Ford [=-
  640. X *
  641. X ************************************************************/
  642. X
  643. X#include <stdio.h>
  644. X#include <fcntl.h>
  645. X#include <ctype.h>
  646. X#include <pwd.h>
  647. X#include <sys/types.h>
  648. X#include <sys/param.h>
  649. X#include <sys/sysmacros.h>
  650. X#include <sys/stat.h>
  651. X#include <sys/tune.h>
  652. X#include <sys/inode.h>
  653. X#include <sys/file.h>
  654. X#include <sys/user.h>
  655. X#include <sys/proc.h>
  656. X#include <sys/signal.h>
  657. X#include <a.out.h>
  658. X
  659. X/* get rid of meaningless NOFILE from param.h */
  660. X#ifdef NOFILE
  661. X#undef NOFILE
  662. X#endif
  663. X
  664. Xextern char *sbrk();
  665. Xextern long lseek();
  666. Xextern void perror(), exit();
  667. Xextern struct passwd *getpwuid();
  668. X
  669. X
  670. Xchar *progname;
  671. X
  672. X#define tuhiaddr (mysyms[0].n_value)
  673. X#define inodeaddr (mysyms[1].n_value)
  674. X#define fileaddr (mysyms[2].n_value)
  675. X#define procaddr (mysyms[3].n_value)
  676. X#define nofileaddr (mysyms[4].n_value)
  677. X
  678. Xstruct nlist mysyms[] =
  679. X{
  680. X    { "tuhi", },
  681. X    { "inode", },
  682. X    { "file", },
  683. X    { "proc", },
  684. X    { "nofile", },
  685. X    { (char *)0, },
  686. X};
  687. X
  688. Xchar buf[BUFSIZ];
  689. X
  690. Xint kmem, mem, kflag, uflag;
  691. Xint NINODE, NFILE, NPROC, NOFILE;
  692. X
  693. Xstruct inode *inode;
  694. Xstruct file *file;
  695. Xstruct proc *proc;
  696. X
  697. X
  698. X/* main program for fuser(1M), a program which lists */
  699. X/* processes that are using the given file(s) */
  700. Xmain(argc, argv)
  701. Xint argc;
  702. Xchar *argv[];
  703. X{
  704. X    int status=0;
  705. X
  706. X    progname = *argv;
  707. X
  708. X    setup();
  709. X
  710. X    while (++argv,--argc)
  711. X    if ((*argv)[0]=='-')
  712. X    {
  713. X        register char c, *i;
  714. X
  715. X        kflag=uflag=0;
  716. X
  717. X        i = *argv+1;
  718. X        while (c= *i++) switch(c)
  719. X        {
  720. X        case 'k':
  721. X        ++kflag;
  722. X        break;
  723. X        case 'u':
  724. X        ++uflag;
  725. X        break;
  726. X        default:
  727. X        fprintf(stderr, "%s: bad flag `-%c'\n", progname, c);
  728. X        fprintf(stderr,
  729. X            "Usage: %s [-ku] files [[-] [-ku] files]\n",
  730. X            progname);
  731. X        return -1;
  732. X        }
  733. X    }
  734. X    else
  735. X        status += fuser(*argv);
  736. X
  737. X    return status;
  738. X}
  739. X
  740. X
  741. X/* a fast, zeroizing, memory allocator for things */
  742. X/* that will never need to be freed */
  743. Xchar *myalloc(nbytes)
  744. Xlong nbytes;
  745. X{
  746. X    register char *ptr = sbrk((int)nbytes);
  747. X
  748. X    if ((long)ptr < 0L)
  749. X    {
  750. X    sprintf(buf, "%s: no memory!", progname);
  751. X    perror(buf);
  752. X    exit(1);
  753. X    }
  754. X
  755. X    return ptr;
  756. X}
  757. X
  758. X
  759. X/* one-time setup of main data structures from the kernel */
  760. Xsetup()
  761. X{
  762. X    struct tunable tune;
  763. X
  764. X    if ( (kmem=open("/dev/kmem", O_RDONLY)) < 0 )
  765. X    {
  766. X    sprintf(buf, "%s: can't open /dev/kmem", progname);
  767. X    perror(buf);
  768. X    exit(1);
  769. X    }
  770. X
  771. X    if ( (mem=open("/dev/mem", O_RDONLY)) < 0 )
  772. X    {
  773. X    sprintf(buf, "%s: can't open /dev/mem", progname);
  774. X    perror(buf);
  775. X    exit(1);
  776. X    }
  777. X
  778. X    if (nlist("/unix", mysyms))
  779. X    {
  780. X    sprintf(buf, "%s: can't nlist /unix", progname);
  781. X    perror(buf);
  782. X    exit(1);
  783. X    }
  784. X
  785. X    setuid(getuid());
  786. X
  787. X    kcopy((char *)&NOFILE, nofileaddr, (long) sizeof NOFILE);
  788. X
  789. X#ifdef DEBUG
  790. X    fprintf(stderr, "tuhi:    0x%08lx\n", tuhiaddr);
  791. X#endif DEBUG
  792. X    kcopy((char *)&tune, tuhiaddr, (long) sizeof tune);
  793. X
  794. X    /* do indirection on these addresses, since they */
  795. X    /* are just pointers in the kernel */
  796. X    kcopy((char *)&inodeaddr, inodeaddr, (long) sizeof inodeaddr);
  797. X    kcopy((char *)&fileaddr, fileaddr, (long) sizeof fileaddr);
  798. X    kcopy((char *)&procaddr, procaddr, (long) sizeof procaddr);
  799. X
  800. X#ifdef DEBUG
  801. X    fprintf(stderr, "inode:    0x%08lx\n", inodeaddr);
  802. X    fprintf(stderr, "file:    0x%08lx\n", fileaddr);
  803. X    fprintf(stderr, "proc:    0x%08lx\n", procaddr);
  804. X#endif DEBUG
  805. X
  806. X    NINODE = tune.ninode;
  807. X    NFILE = tune.nfile;
  808. X    NPROC = tune.nproc;
  809. X
  810. X#ifdef DEBUG
  811. X    fprintf(stderr, "NOFILE:    %d\n", NOFILE);
  812. X    fprintf(stderr, "NINODE:    %d\n", NINODE);
  813. X    fprintf(stderr, "NFILE:    %d\n", NFILE);
  814. X    fprintf(stderr, "NPROC:    %d\n", NPROC);
  815. X#endif DEBUG
  816. X
  817. X    inode = (struct inode *)myalloc((long) sizeof (struct inode) * NINODE);
  818. X    file = (struct file *)myalloc((long) sizeof (struct file) * NFILE);
  819. X    proc = (struct proc *)myalloc((long) sizeof (struct proc) * NPROC);
  820. X
  821. X    kcopy((char *)inode, inodeaddr, (long) sizeof (struct inode) * NINODE);
  822. X    kcopy((char *)file, fileaddr, (long) sizeof (struct file) * NFILE);
  823. X    kcopy((char *)proc, procaddr, (long) sizeof (struct proc) * NPROC);
  824. X}
  825. X
  826. X
  827. X/* copy bytes from physical address space to this process */
  828. Xpcopy(caddr, paddr, nbytes)
  829. Xchar *caddr;
  830. Xlong paddr;
  831. Xlong nbytes;
  832. X{
  833. X    if ( lseek(mem, paddr, 0)<0L ||
  834. X    read(mem, caddr, (unsigned)nbytes) != nbytes )
  835. X    {
  836. X    sprintf(buf, "%s: can't read /dev/mem", progname);
  837. X    perror(buf);
  838. X    exit(1);
  839. X    }
  840. X}
  841. X
  842. X
  843. X/* copy bytes from kernel address space to this process */
  844. Xkcopy(caddr, kaddr, nbytes)
  845. Xchar *caddr;
  846. Xlong kaddr;
  847. Xlong nbytes;
  848. X{
  849. X    if ( lseek(kmem, kaddr, 0)<0L ||
  850. X    read(kmem, caddr, (unsigned)nbytes) != nbytes )
  851. X    {
  852. X    sprintf(buf, "%s: can't read /dev/kmem", progname);
  853. X    perror(buf);
  854. X    exit(1);
  855. X    }
  856. X}
  857. X
  858. X
  859. X/* Return a pointer to a local copy of the user structure */
  860. X/* for process number `procidx'.  Returns NULL if procidx */
  861. X/* refers to an invalid (not-in-use or otherwise) slot. */
  862. Xstruct user *getuser(procidx)
  863. Xint procidx;
  864. X{
  865. X    static struct user **users;
  866. X    struct file **ofile;
  867. X    long upage;
  868. X
  869. X    if (!proc[procidx].p_stat ||
  870. X    proc[procidx].p_stat == SIDL ||
  871. X    proc[procidx].p_stat == SZOMB)
  872. X    return 0;
  873. X
  874. X    if (!(proc[procidx].p_flag & SLOAD))
  875. X    {
  876. X    /* can't handle swapped process yet */
  877. X    fprintf(stderr, "%s: can't handle swapped process %d (flag=%05x)\n",
  878. X        progname, proc[procidx].p_pid, proc[procidx].p_flag);
  879. X    return 0;
  880. X    }
  881. X
  882. X    if (!users)
  883. X    users = (struct user **)myalloc((long) sizeof (struct user *) * NPROC);
  884. X
  885. X    if (!users[procidx])
  886. X    {
  887. X    upage = (long)ctob(proc[procidx].p_addr[0]);
  888. X
  889. X    /* allocate and copy in the user structure */
  890. X    users[procidx] = (struct user *)myalloc((long) sizeof (struct user));
  891. X    pcopy((char *)(users[procidx]),
  892. X          upage + U_OFFSET,
  893. X          (long) sizeof (struct user));
  894. X
  895. X    /* allocate and copy in the list of file pointers */
  896. X    ofile = (struct file **)myalloc((long) sizeof (struct file *) * NOFILE);
  897. X    pcopy((char *)ofile,
  898. X          upage+(long)(users[procidx]->u_ofile)-VPG_BASE,
  899. X          (long) sizeof (struct file *) * NOFILE);
  900. X    users[procidx]->u_ofile = ofile;
  901. X    }
  902. X
  903. X    return users[procidx];
  904. X}
  905. X
  906. X
  907. X/* find all users of the file `name' */
  908. Xfuser(name)
  909. Xchar *name;
  910. X{
  911. X    register i;
  912. X    int filesys;
  913. X    struct stat Stat;
  914. X
  915. X    if (stat(name, &Stat))
  916. X    {
  917. X    sprintf(buf, "%s: can't stat %s", progname, name);
  918. X    perror(buf);
  919. X    return 1;
  920. X    }
  921. X
  922. X    /* see if we are looking for a whole filesystem */
  923. X    filesys = ((Stat.st_mode&S_IFMT) == S_IFBLK);
  924. X
  925. X#ifdef DEBUG
  926. X    if (filesys)
  927. X    fprintf(stderr, "looking for files on dev=%d,%d\n",
  928. X        bmajor(Stat.st_rdev), minor(Stat.st_rdev));
  929. X    else
  930. X    fprintf(stderr, "looking for dev=%d,%d, ino=%d\n",
  931. X        bmajor(Stat.st_dev), minor(Stat.st_dev), Stat.st_ino);
  932. X#endif DEBUG
  933. X
  934. X    for ( i=0 ; i<NINODE ; ++i )
  935. X    {
  936. X    if ( inode[i].i_count &&
  937. X         (filesys
  938. X         ? (brdev(inode[i].i_dev) == Stat.st_rdev)
  939. X         : (brdev(inode[i].i_dev) == Stat.st_dev &&
  940. X            inode[i].i_number == Stat.st_ino)) )
  941. X    {
  942. X#ifdef DEBUG
  943. X        fprintf(stderr, "Found it!  inode[%d], i_size is %ld\n",
  944. X           i, inode[i].i_size);
  945. X#endif DEBUG
  946. X
  947. X        iuser((struct inode *)inodeaddr + i);
  948. X    }
  949. X    }
  950. X
  951. X    putchar('\n');
  952. X
  953. X    return 0;
  954. X}
  955. X
  956. X
  957. X#define CHECK(kaddr, type) if (kaddr==kinode) { if (++flag==1) printf(" %d", proc[i].p_pid); if (type) putchar(type); }
  958. X
  959. X/* find all users of the inode at kernel address `kinode' */
  960. Xiuser(kinode)
  961. Xstruct inode *kinode;
  962. X{
  963. X    register int i, j;
  964. X    int flag;
  965. X    struct user *user;
  966. X    struct passwd *pwd;
  967. X
  968. X#ifdef DEBUG
  969. X    fprintf(stderr, "Looking for users of inode at kernel address 0x%08lx\n",
  970. X        kinode);
  971. X#endif DEBUG
  972. X
  973. X    for ( i=0 ; i<NPROC ; ++i )
  974. X    if (user = getuser(i))
  975. X    {
  976. X#ifdef DEBUG
  977. X        fprintf(stderr, "%03d: pid=%5d addr[0]=%05x addr[1]=%05x swaddr=%05x\n",
  978. X            i, proc[i].p_pid, proc[i].p_addr[0], proc[i].p_addr[1],
  979. X            proc[i].p_swaddr);
  980. X#endif DEBUG
  981. X
  982. X#ifdef DEBUG
  983. X        fprintf(stderr, "    user = 0x%08lx\n", user);
  984. X        fprintf(stderr, "    user->u_ofile = 0x%08lx\n", user->u_ofile);
  985. X#endif DEBUG
  986. X
  987. X        fflush(stderr);
  988. X        flag=0;
  989. X        CHECK(user->u_cdir, 'c');
  990. X        CHECK(user->u_rdir, 'r');
  991. X        CHECK(user->u_pdir, 'p');
  992. X        for ( j=0 ; !flag && j<NOFILE ; ++j )
  993. X        if (user->u_ofile[j])
  994. X            CHECK(file[user->u_ofile[j]-(struct file *)fileaddr].f_inode, 0);
  995. X        fflush(stdout);
  996. X
  997. X        if (flag)
  998. X        {
  999. X        if (uflag)
  1000. X        {
  1001. X            if ( (pwd=getpwuid((int)proc[i].p_uid)) )
  1002. X            fprintf(stderr, "(%s)", pwd->pw_name);
  1003. X            else
  1004. X            fprintf(stderr, "(%d)", proc[i].p_uid);
  1005. X        }
  1006. X        if (kflag && proc[i].p_pid)
  1007. X            if (kill(proc[i].p_pid, SIGKILL))
  1008. X            {
  1009. X            sprintf(buf, "%s: can't kill process %d",
  1010. X                progname, proc[i].p_pid);
  1011. X            perror(buf);
  1012. X            }
  1013. X        }
  1014. X    }
  1015. X}
  1016. SHAR_EOF
  1017. fi
  1018. exit 0
  1019. #    End of shell archive
  1020.